package sudoku

import "errors"

// Position Generator is used by sudokuChecker
// To generate position by unit(row, col, block)
// For easy to check

// Generator State, check row, col and block
type positionGeneratorState int

const (
	gRow positionGeneratorState = iota
	gCol
	gBlock
)

// generator to generate position in sudoku
type positionGenerator struct {
	state positionGeneratorState
	// reprents 2-d array unitIndex(unit), eleIndex(ele in unit)
	unitIndex, eleIndex int
}

func newPositionGenerator() *positionGenerator {
	return &positionGenerator{}
}

// SetState set generator state to produce (i, j)
func (g *positionGenerator) SetState(state positionGeneratorState) {
	g.state = state
	// reset all index
	g.unitIndex, g.eleIndex = 0, 0
}

func (g *positionGenerator) GetState() positionGeneratorState {
	return g.state
}

// Next will step to next position
// When step to next unit, will return nextUnitFlag
// The first still return true
func (g *positionGenerator) Next() (i, j int, nextUnitFlag bool, err error) {
	if g.unitIndex >= 9 {
		i, j, nextUnitFlag = -1, -1, false
		err = errors.New("Reach the end")
		return
	}
	// when eleIndex = 0, means change to next unit
	if g.eleIndex == 0 {
		nextUnitFlag = true
	} else {
		nextUnitFlag = false
	}
	switch g.state {
	case gRow:
		i, j = g.unitIndex, g.eleIndex
	case gCol:
		i, j = g.eleIndex, g.unitIndex
	case gBlock:
		i = (g.eleIndex / 3) + (g.unitIndex/3)*3
		j = (g.eleIndex % 3) + (g.unitIndex%3)*3
	}
	g.eleIndex++
	// step to next
	if g.eleIndex >= 9 {
		g.eleIndex = 0
		g.unitIndex++
	}
	err = nil
	return
}
